package com.zrc.japktool.apk.check;

import com.google.gson.Gson;
import com.zrc.japktool.apk.xapk2apk.ManifestGsonBean;
import com.zrc.japktool.util.TaskLog;
import net.lingala.zip4j.ZipFile;
import net.lingala.zip4j.io.inputstream.ZipInputStream;
import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.model.LocalFileHeader;
import pxb.android.axml.Axml;
import pxb.android.axml.AxmlReader;

import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class CheckGame {
    private TaskLog log = null;

    public CheckGame(TaskLog log) {
        this.log = log;
    }

    public void checkApk(String apkPath) throws Exception {
        Set<String> filter = new HashSet<>();
        //检测apk的so文件
        ZipFile zipFile = new ZipFile(apkPath);
        List<FileHeader> files = zipFile.getFileHeaders();
        for (FileHeader fileHeader : files) {
            if (!fileHeader.isDirectory() && fileHeader.getFileName().contains("lib/arm64-v8a/")) {
                filter.add(fileHeader.getFileName().replace("lib/arm64-v8a/", ""));
            }
        }
        if (!filter.contains("libunity.so")) {
            log.error("游戏检测: 不合规：缺少libunity.so,不是unity游戏...");
            return;
        }
        if (!filter.contains("libil2cpp.so")) {
            log.error("游戏检测: 不合规：缺少libil2cpp.so,不是unity游戏...");
            return;
        }
        if (filter.contains("libpairipcore.so")) {
            log.error("游戏检测: 不合规：有libpairipcore.so库,无法过goole校验 ,存在逆向问题...");
            return;
        }
        InputStream manifestIs = zipFile.getInputStream(zipFile.getFileHeader("AndroidManifest.xml"));
        AxmlReader rd = new AxmlReader(manifestIs.readAllBytes());
        Axml axml = new Axml();
        rd.accept(axml);
        Axml.Node manifest = axml.findFirst("manifest");
        Axml.Node application = manifest.findFirst("application");
        for (Axml.Node child : application.children) {
            if (child.name.equals("activity")) {
                for (Axml.Node.Attr attr : child.attrs) {
                    if (attr.name.equals("name") && attr.value.toString().contains("com.pairip.licensecheck")) {
                        log.error("游戏检测: 不合规：com.pairip.licensecheck,逆向出来会崩溃...");
                        return;
                    }
                }
            }
        }
        log.tip("游戏检测: 合规");
    }

    public void checkXApk(String xapkPaht) throws Exception {
        ZipFile aZip = new ZipFile(xapkPaht);
        FileHeader manifestGsonFile = aZip.getFileHeader("manifest.json");
        InputStream inputStream = aZip.getInputStream(manifestGsonFile);
        String gsonStr = new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);
        inputStream.close();
        ManifestGsonBean manifestGsonBean = new Gson().fromJson(gsonStr, ManifestGsonBean.class);

        String abiApkZipName = "config.arm64_v8a.apk";
        FileHeader abiZipFileHeader = aZip.getFileHeader(abiApkZipName);
        if (abiZipFileHeader == null) {
            log.error("游戏检测: 不合规：缺少config.arm64_v8a.apk,xapk包不完整...");
            return;
        }

        InputStream abiZipIs = aZip.getInputStream(abiZipFileHeader);
        ZipInputStream abiZipZis = new ZipInputStream(abiZipIs);// 使用ZipInputStream处理B.zip
        LocalFileHeader fileHeader;
        Set<String> filter = new HashSet<>();
        while ((fileHeader = abiZipZis.getNextEntry()) != null) {
            if (!fileHeader.isDirectory() && fileHeader.getFileName().contains("lib/arm64-v8a/")) {
                filter.add(fileHeader.getFileName().replace("lib/arm64-v8a/", ""));
            }
        }
        if (!filter.contains("libunity.so")) {
            log.error("游戏检测: 不合规：缺少libunity.so,不是unity游戏...");
            return;
        }
        if (!filter.contains("libil2cpp.so")) {
            log.error("游戏检测: 不合规：缺少libil2cpp.so,不是unity游戏...");
            return;
        }
        if (filter.contains("libpairipcore.so")) {
            log.error("游戏检测: 不合规：有libpairipcore.so库,无法过goole校验 ,存在逆向问题...");
            return;
        }

        //清单文件校验
        String mainApkName = manifestGsonBean.getPackage_name() + ".apk";
        FileHeader mainApkFileHeader = aZip.getFileHeader(mainApkName);
        if (mainApkFileHeader == null) {
            log.error("游戏检测: 不合规：缺少" + manifestGsonBean.getPackage_name() + ".apk,xapk包不完整...");
            return;
        }
        InputStream mainApkInputStream = aZip.getInputStream(mainApkFileHeader);
        ZipInputStream mainApkInputZipInputStream = new ZipInputStream(mainApkInputStream);
        while ((fileHeader = mainApkInputZipInputStream.getNextEntry()) != null) {
            if (!fileHeader.isDirectory() && fileHeader.getFileName().equals("AndroidManifest.xml")) {
                byte[] manifestBytes = mainApkInputZipInputStream.readAllBytes();
                AxmlReader axmlReader = new AxmlReader(manifestBytes);
                Axml axml = new Axml();
                axmlReader.accept(axml);
                Axml.Node manifest = axml.findFirst("manifest");
                Axml.Node application = manifest.findFirst("application");
                for (Axml.Node child : application.children) {
                    if (child.name.equals("activity")) {
                        for (Axml.Node.Attr attr : child.attrs) {
                            if (attr.name.equals("name") && attr.value.toString().contains("com.pairip.licensecheck")) {
                                log.error("游戏检测: 不合规：com.pairip.licensecheck,逆向出来会崩溃...");
                                return;
                            }
                        }
                    }
                }
                break;
            }
        }
        log.tip("合规");
    }

    public void checkGame(String filePath){
        try {
            log.tip("游戏检测: 开始...");
            try {
                if (filePath.endsWith(".apk")) {
                    checkApk(filePath);
                } else {
                    checkXApk(filePath);
                }
            } catch (Exception e) {
                log.error("游戏检测: 失败: " + e.getMessage());
            } finally {
                log.tip("游戏检测: 结束...");
            }
        }catch (Exception e){
            log.error("游戏检测: 失败: " + e.getMessage());
        }
    }
}
